home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2append.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  9.8 KB  |  363 lines

  1. /*===================================================================
  2.  *
  3.  * FILE:
  4.  *   prs2append.c
  5.  *
  6.  * IDENTIFICATION:
  7.  *   $Header: /private/postgres/src/rules/prs2/RCS/prs2append.c,v 1.14 1991/07/16 13:14:16 sp Exp $
  8.  *
  9.  * DESCRIPTION:
  10.  *
  11.  *
  12.  *===================================================================
  13.  */
  14.  
  15. #include "tmp/c.h"
  16. #include "access/heapam.h"
  17. #include "access/htup.h"
  18. #include "storage/buf.h"
  19. #include "utils/rel.h"
  20. #include "utils/log.h"
  21. #include "utils/palloc.h"
  22. #include "rules/prs2.h"
  23. #include "rules/prs2stub.h"
  24. #include "nodes/execnodes.h"        /* which includes access/rulescan.h */
  25. #include "parser/parse.h"        /* for the APPEND */
  26.  
  27. /*-------------------------------------------------------------------
  28.  *
  29.  * prs2Append
  30.  */
  31. Prs2Status
  32. prs2Append(prs2EStateInfo, relationRuleInfo, explainRelation,
  33.         tuple, buffer, relation, returnedTupleP, returnedBufferP)
  34. Prs2EStateInfo prs2EStateInfo;
  35. RelationRuleInfo relationRuleInfo;
  36. Relation explainRelation;
  37. HeapTuple tuple;
  38. Buffer buffer;
  39. Relation relation;
  40. HeapTuple *returnedTupleP;
  41. Buffer *returnedBufferP;
  42. {
  43.     RuleLock locks, newLocks, explocks, temp;
  44.     Prs2Stub stubs;
  45.     AttributeValues attrValues;
  46.     AttributeNumber numberOfAttributes, attrNo;
  47.     bool insteadRuleFound;
  48.     Name relName;
  49.     Prs2Status status;
  50.     int i;
  51.     TupleDescriptor tupDesc;
  52.  
  53.     /*
  54.      * NOTE: currently we only have relation-level-locks for
  55.      * "on append ...." rules.
  56.      * So we do not check for any tuple level locks.
  57.      * (after all this is a brand new tuple with no locks on it)
  58.      */
  59.     relName = RelationGetRelationName(relation);
  60.     tupDesc = RelationGetTupleDescriptor(relation);
  61.  
  62.     locks = relationRuleInfo->relationLocks;
  63.     stubs = relationRuleInfo->relationStubs;
  64.  
  65.     /*
  66.      * now extract from the tuple the array of the attribute values.
  67.      */
  68.     attrValues = attributeValuesCreate(tuple, buffer, relation);
  69.  
  70.     /*
  71.      * activate 'on append' rules...
  72.      */
  73.     if (locks == NULL || prs2GetNumberOfLocks(locks)==0) {
  74.     /*
  75.      * the trivial case: no "on append" rules!
  76.      */
  77.     status = PRS2_STATUS_TUPLE_UNCHANGED;
  78.     insteadRuleFound = false;
  79.     *returnedTupleP = tuple;
  80.     *returnedBufferP = buffer;
  81.     } else {
  82.     /*
  83.      * first calculate all the attributes of the tuple.
  84.      * I.e. see if there is any rule that will calculate a new
  85.      * value for a tuple's attribute (i.e. a backward chaining rule).
  86.      */
  87.     numberOfAttributes = RelationGetNumberOfAttributes(relation);
  88.     for (attrNo=1; attrNo <= numberOfAttributes; attrNo++) {
  89.         prs2ActivateBackwardChainingRules(
  90.             prs2EStateInfo,
  91.             explainRelation,
  92.             relation,
  93.             attrNo,
  94.             PRS2_NEW_TUPLE,
  95.             InvalidObjectId,
  96.             InvalidAttributeValues,
  97.             InvalidRuleLock,
  98.             LockTypeInvalid,
  99.             tuple->t_oid,
  100.             attrValues,
  101.             locks,
  102.             LockTypeAppendWrite,
  103.             (AttributeNumberPtr) NULL,
  104.             (AttributeNumber) 0);
  105.     }
  106.  
  107.     /*
  108.      * now, try to activate all other 'on append' rules.
  109.      * (these ones will have a LockTypeAppendAction lock ....)
  110.      * NOTE: the attribute number stored in the locks for these
  111.      * rules must be `InvalidAttributeNumber' because they
  112.      * do not refer to any attribute in particular.
  113.      */
  114.     prs2ActivateForwardChainingRules(
  115.         prs2EStateInfo,
  116.         explainRelation,
  117.         relation,
  118.         InvalidAttributeNumber,
  119.         LockTypeAppendAction,
  120.         PRS2_NEW_TUPLE,
  121.         InvalidObjectId,
  122.         InvalidAttributeValues,
  123.         InvalidRuleLock,
  124.         LockTypeInvalid,
  125.         tuple->t_oid,
  126.         attrValues,
  127.         locks,
  128.         LockTypeAppendWrite,
  129.         &insteadRuleFound,
  130.         (AttributeNumberPtr) NULL,
  131.         (AttributeNumber) 0);
  132.  
  133.     /*
  134.      * Now all the correct values for the new tuple
  135.      * (the ones proposed by the user + the ones calculated
  136.      * by rule with 'LockTypeAppendWrite' locks,
  137.      * are in the attrValues array.
  138.      * Create a new tuple with the correct values.
  139.      */
  140.     if (attributeValuesMakeNewTuple(
  141.                     tuple, buffer,
  142.                     attrValues, locks,
  143.                     LockTypeRetrieveWrite,
  144.                     relation, returnedTupleP)) {
  145.         status = PRS2_STATUS_TUPLE_CHANGED;
  146.         *returnedBufferP = InvalidBuffer;
  147.     } else {
  148.         status = PRS2_STATUS_TUPLE_UNCHANGED;
  149.         *returnedTupleP = tuple;
  150.         *returnedBufferP = buffer;
  151.     }
  152.     }
  153.  
  154.  
  155.     /*
  156.      * OK, if there was an 'instead' rule, then we must not
  157.      * append the tuple.
  158.      */
  159.     if (insteadRuleFound) {
  160.     return(PRS2_STATUS_INSTEAD);
  161.     }
  162.  
  163.     /*
  164.      * well, there was no instead rule.
  165.      * Check all the stubs to see if this tuple should
  166.      * inherit some new locks.
  167.      */
  168.     newLocks = prs2FindLocksForNewTupleFromStubs(
  169.             *returnedTupleP,
  170.             *returnedBufferP,
  171.             stubs,
  172.             relation);
  173.     /*
  174.      * Check if any "export" lock should be added to the
  175.      * tuple. If yes, then activate the appropriate
  176.      * rule plans...
  177.      */
  178.     explocks = prs2FindNewExportLocksFromLocks(newLocks);
  179.     for (i=0; i<prs2GetNumberOfLocks(explocks); i++) {
  180.     Prs2OneLock oneLock;
  181.     AttributeNumber attrno;
  182.     oneLock = prs2GetOneLockFromLocks(explocks,i);
  183.     attrno = prs2OneLockGetAttributeNumber(oneLock);
  184.     if (!attrValues[attrno-1].isNull)
  185.         prs2ActivateExportLockRulePlan(oneLock,
  186.                     attrValues[attrno-1].value,
  187.                     tupDesc->data[attrno-1]->atttypid,
  188.                     APPEND);
  189.     }
  190.  
  191.     /*
  192.      * the locks that this tuple must get is the union of 'newLocks'
  193.      * and 'explocks'.
  194.      */
  195.     temp = prs2LockUnion(newLocks, explocks);
  196.     prs2FreeLocks(newLocks);
  197.     prs2FreeLocks(explocks);
  198.     newLocks = temp;
  199.  
  200.     attributeValuesFree(attrValues, relation);
  201.  
  202.     /*
  203.      * Did the locks or an attribute of the tuple change?
  204.      * If yes, whistle to the executor...
  205.      */
  206.     if (status == PRS2_STATUS_TUPLE_CHANGED) {
  207.     if (prs2GetNumberOfLocks(newLocks) == 0) {
  208.         prs2FreeLocks(newLocks);
  209.         return(PRS2_STATUS_TUPLE_CHANGED);
  210.     } else {
  211.         HeapTupleSetRuleLock(*returnedTupleP, InvalidBuffer, newLocks);
  212.         return(PRS2_STATUS_TUPLE_CHANGED);
  213.     }
  214.     } else {    /* status = PRS2_STATUS_TUPLE_UNCHANGED */
  215.     if (prs2GetNumberOfLocks(newLocks) == 0) {
  216.         prs2FreeLocks(newLocks);
  217.         return(PRS2_STATUS_TUPLE_UNCHANGED);
  218.     } else {
  219.         /*
  220.          * we must create a COPY of the tuple!
  221.          */
  222.         *returnedTupleP = palloctup(tuple,buffer,relation);
  223.         HeapTupleSetRuleLock(*returnedTupleP, InvalidBuffer, newLocks);
  224.         *returnedBufferP = InvalidBuffer;
  225.         return(PRS2_STATUS_TUPLE_CHANGED);
  226.     }
  227.     }
  228. }
  229.  
  230. /*-----------------------------------------------------------------------
  231.  * prs2FindLocksForNewTupleFromStubs
  232.  *
  233.  * Given a brand new tuple that will be inserted in a relation,
  234.  * check all the rule stubs to find what tuple-level locks this tuple
  235.  * should get.
  236.  *
  237.  * NOTE: the following code can be hazardus to your mental health...
  238.  * (but if you are hacking it you have already reached the point of no
  239.  * return, so...)
  240.  *
  241.  * The idea is that we have a new tuple, some stubs and we want to see
  242.  * which of the stubs' qualifications are satisfied by the tuple.
  243.  * So, all we need is to test if the tuple satisfies the stub's
  244.  * qualification, eh? Trivial! Easy! 5 lines of code!
  245.  * NOOOOOOO! This is NOT enough! The problem is that a stub's
  246.  * qualification must also be considered "satisfied" if it depends on
  247.  * an attribute with a "write" lock.
  248.  * So, for every new "write" lock added, we must re-check all the
  249.  * previous stubs to see if they "depend" on this lock. Bliah!
  250.  * 
  251.  *-----------------------------------------------------------------------
  252.  */
  253. RuleLock
  254. prs2FindLocksForNewTupleFromStubs(tuple, buffer, stubs, relation)
  255. HeapTuple tuple;
  256. Buffer buffer;
  257. Prs2Stub stubs;
  258. Relation relation;
  259. {
  260.     TupleDescriptor tdesc;
  261.     Prs2OneStub thisStub;
  262.     LispValue thisQual;
  263.     Prs2OneLock thisLock;
  264.     Prs2LockType locktype;
  265.     bool done;
  266.     RuleLock res, t;
  267.     bool *used;
  268.     register int i, j;
  269.  
  270.     /*
  271.      * check the trival case...
  272.      */
  273.     if (stubs->numOfStubs == 0) {
  274.     res = prs2MakeLocks();
  275.     return(res);
  276.     }
  277.  
  278.     /*
  279.      * keep an array of the stubs that "succeeded" in adding
  280.      * locks to the tuple.
  281.      */
  282.     used = (bool *) palloc(stubs->numOfStubs * sizeof(bool));
  283.     if (used == NULL) {
  284.     elog(WARN,"prs2FindLocksForNewTupleFromStubs: out of memory");
  285.     }
  286.     for (i=0; i<stubs->numOfStubs; i++)
  287.     used[i] = false;
  288.  
  289.     tdesc = RelationGetTupleDescriptor(relation);
  290.     res = prs2MakeLocks();
  291.  
  292.     /*
  293.      * Yes, I know, this code sure looks ugly, but it must work
  294.      * by tonight! When (if!) I have some more time I'll clean it
  295.      * & speed it up a little...
  296.      */
  297.     do {
  298.     done = true;
  299.     /*
  300.      * check one by one all stubs...
  301.      */
  302.     for (i=0; i<stubs->numOfStubs; i++) {
  303.         if (used[i]) {
  304.         /*
  305.          * no need to check this stub again
  306.          */
  307.         continue;
  308.         }
  309.         thisStub = stubs->stubRecords[i];
  310.         thisQual = thisStub->qualification;
  311.         /*
  312.          * should we use the lock of this stub?
  313.          * The answer is yes iff the tuple satisfies
  314.          * the stub's qual or if the qual depends
  315.          * on an attribute which has a "write" lock on it.
  316.          */
  317.         if (prs2StubQualTestTuple(tuple, buffer, tdesc, thisQual)) {
  318.         used[i] = true;
  319.         } else {
  320.         for (j=0; j<prs2GetNumberOfLocks(res); j++) {
  321.             thisLock = prs2GetOneLockFromLocks(res, j);
  322.             locktype = prs2OneLockGetLockType(thisLock);
  323.             if (locktype == LockTypeRetrieveWrite) {
  324.             /*
  325.              * does this stub depend on the attribute
  326.              * "calculated" by this "write" lock?
  327.              */
  328.             if (prs2DoesStubDependsOnAttribute(thisStub,
  329.                 prs2OneLockGetAttributeNumber(thisLock))){
  330.                 used[i] = true;
  331.                 break;
  332.             }
  333.             }
  334.         }
  335.         }
  336.         if (used[i]) {
  337.         /*
  338.          * OK, we must use this attribute.
  339.          * Add its lock to the 'res'
  340.          */
  341.         t = prs2LockUnion(res, thisStub->lock);
  342.         prs2FreeLocks(res);
  343.         res = t;
  344.         /*
  345.          * if this stub had a "write" lock, then
  346.          * 'done' is false because we must check again
  347.          * all the stubs.
  348.          */
  349.         for (j=0; j<prs2GetNumberOfLocks(thisStub->lock); j++) {
  350.             thisLock = prs2GetOneLockFromLocks(thisStub->lock, j);
  351.             locktype = prs2OneLockGetLockType(thisLock);
  352.             if (locktype == LockTypeRetrieveWrite) {
  353.             done = false;
  354.             break;
  355.             }
  356.         }
  357.         }
  358.     }
  359.     } while (!done);
  360.  
  361.     return(res);
  362. }
  363.